跳到主要内容

Go 中基本的数据结构

数组(值传递)

定义一个固定数组

注意!!!数组⻓度必须是常量

import "fmt"

func main() {
var arr [10]int // 都是 0
// 或者这样定义
arr2 := [10]int{1, 2, 3, 4} // 后面的都是零

// 遍历 1:使用 for
for i := 0; i < 10; i++ {
fmt.Printf("%d ", arr[i])
}

// 遍历 2:使用 range 关键字(i 是索引,v 是 value)
for i, v := range arr {
fmt.Printf("%d,%d ", i, v)
}
}

数组传参有点麻烦,这个数组大小的不同数组对象也是不同的,例如 [10]int[3]int 是不同的对象类型,如下,这个 fun1 就不能传入 [3]int 类型,只能传 [10]int 类型

而且注意!! 这种传递数组的方式是值拷贝的,不是引用传递,所以修改这里的数组是不会影响原始数组的

func fun1(arr [10]int) {
// 如果不需要 index 可以使用 _ 来表示匿名变量
for _, v := range arr {
fmt.Println(v)
}
}

数组的操作,使用 ... 可以省略指定长度,Go 会根据元素个数来计算长度

arr := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println("arr[2:6]=", arr[2:6]) //arr[2:6]= [2 3 4 5]
fmt.Println("arr[:6]=", arr[:6]) //arr[:6]= [0 1 2 3 4 5]
fmt.Println("arr[2:]=", arr[2:]) //arr[2:]= [2 3 4 5 6 7 8 9]
fmt.Println("arr[:]=", arr[:]) //arr[:]= [0 1 2 3 4 5 6 7 8 9]

创建多维数组

Go语言支持嵌套数组,即多维数组。如下代码声明了一个二维数组:

//声明一个二维数组,该数组以两个数组作为元素,其中每个数组又有4个int类型的元素
doubleArray := [2][4] int {[4] int {1,2,3,4}, [4] int {5,6,7,8}}

//简化上述声明,直接忽略内部类型
easyArray := [2][4] int {{1,2,3,4},{5,6,7,8}}

创建动态多维数组

func main() {
m, n := 3, 4
a := make([][]int, m) // 二维切片,3行
for i := range a {
a[i] = make([]int, n) // 每一行4列
}
fmt.Println(a)
}

container/list 链表

package main

import (
"container/list"
"fmt"
)

func main() {
nums := list.New()
nums.PushBack(1)
nums.PushBack(2)
nums.PushBack(3)
for e := nums.Front(); e != nil; e = e.Next() {
fmt.Println(e.Value)
}
}

container/heap 堆

这个堆用法有点怪异,要使用g o 标准库给我们提供的 heap,那么必须自己实现这些接口定义的方法

Len() int
Less(i, j int) bool
Swap(i, j int)
Push(x interface{})
Pop() interface{}

heap 提供的方法

h := &IntHeap{3, 8, 6}  // 创建IntHeap类型的原始数据
func Init(h Interface) // 对heap进行初始化,生成小根堆(或大根堆)
func Push(h Interface, x interface{}) // 往堆里面插入内容
func Pop(h Interface) interface{} // 从堆顶pop出内容
func Remove(h Interface, i int) interface{} // 从指定位置删除数据,并返回删除的数据
func Fix(h Interface, i int) // 从i位置数据发生改变后,对堆再平衡,优先级队列使用到了该方法

创建一个小根堆

package main

import (
"container/heap"
"fmt"
)

// 需要自己创建一个切片
type IntHeap []int

func (h IntHeap) Len() int {
return len(h)
}

// 如果 h[i] < h[j] 生成的就是小根堆,如果 h[i] > h[j] 生成的就是大根堆
func (h IntHeap) Less(i, j int) bool {
return h[i] < h[j]
}

// 绑定 swap 方法,交换两个元素位置
func (h IntHeap) Swap(i, j int) {
h[i], h[j] = h[j], h[i]
}

// 绑定 push 方法,插入新元素
func (h *IntHeap) Push(x interface{}) {
// 这里要用指针
*h = append(*h, x.(int))
}

// 绑定 pop 方法,从最后拿出一个元素并返回
func (h *IntHeap) Pop() interface{} {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}

// 小根堆使用例子
func main() {
h := &IntHeap{2, 1, 5, 100, 3, 6, 4, 5}
heap.Init(h) // 初始化 heap
heap.Push(h, 3)

fmt.Printf("minimum: %d\n", (*h)[0])
for h.Len() > 0 {
fmt.Printf("%d ", heap.Pop(h))
}
}

输出:

1 2 3 3 4 5 5 6 100

创建一个优先级队列

利用 heap 实现优先级队列

package main

import (
"container/heap"
"fmt"
)

type Item struct {
value string // 优先级队列中的数据,可以是任意类型,这里使用string
priority int // 优先级队列中节点的优先级
index int // index是该节点在堆中的位置
}

// 优先级队列需要实现heap的interface
type PriorityQueue []*Item

// 绑定Len方法
func (pq PriorityQueue) Len() int {
return len(pq)
}

// 绑定Less方法,这里用的是小于号,生成的是小根堆
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].priority < pq[j].priority
}

// 绑定swap方法
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index, pq[j].index = i, j
}

// 绑定put方法,将index置为-1是为了标识该数据已经出了优先级队列了
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
*pq = old[0 : n-1]
item.index = -1
return item
}

// 绑定push方法
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}

// 更新修改了优先级和值的item在优先级队列中的位置
func (pq *PriorityQueue) update(item *Item, value string, priority int) {
item.value = value
item.priority = priority
heap.Fix(pq, item.index)
}

func main() {
// 创建节点并设计他们的优先级
items := map[string]int{"二毛": 5, "张三": 3, "狗蛋": 9}

i := 0
pq := make(PriorityQueue, len(items)) // 创建优先级队列,并初始化
for k, v := range items { // 将节点放到优先级队列中
pq[i] = &Item{
value: k,
priority: v,
index: i}
i++
}

heap.Init(&pq) // 初始化堆

item := &Item{ // 创建一个item
value: "李四",
priority: 1,
}

heap.Push(&pq, item) // 入优先级队列
pq.update(item, item.value, 6) // 更新item的优先级
for len(pq) > 0 {
item := heap.Pop(&pq).(*Item)
fmt.Printf("%.2d:%s index:%.2d\n", item.priority, item.value, item.index)
}
}

Reference

GO语言heap剖析及利用heap实现优先级队列